/*----------------------------------------------------------------------
* Copyright (C) 2013 - 2014: Sergey Smolyannikov <brainstream@yandex.com>
*
* This file is part of lxpamon.
*
* lxpamon is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* lxpamon is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with lxpamon. If not, see http://www.gnu.org/licenses/gpl-3.0.txt.
----------------------------------------------------------------------*/

#include <stdlib.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <lxpanel/plugin.h>
#include "pamon.h"
#include "utils.h"

#define INVALID_VOLUME ~0
#define DEFAULT_FORMAT "%i%%"
#define ALLOWED_FORMAT "i"
#define INVALID_FORMAT_SYMBOL ' '
#define CONFIG_FORMAT "Format"
#define CONFIG_SINK "Sink"
#define CONFIG_BOLD "BoldFont"

typedef struct
{
    Pamon * pamon;
    GtkWidget * label;
    uint32_t current_volume;
    int sink;
    char * format;
    int bold_font;
} PluginData;

static int lxpamonConstructor(Plugin * plugin, char ** config);
static void lxpamonInitConfig(char ** src, PluginData * plug_data);
static void lxpamonDestructor(Plugin * plugin);
static void lxpamonConfigure(Plugin * plugin, GtkWindow * parent);
static void lxpamonApplyConfiguration(Plugin * plugin);
static void lxpamonSaveConfig(Plugin * plugin, FILE * file);
static void lxpamonPanelConfigurationChanged(Plugin * plugin);
static void lxpamonDrawVolume(Plugin * plugin);
static void pamonVolumeChanged(uint32_t current_volume, Plugin * plugin);
static void pamonError(PamonError error, Plugin * plugin);


extern void panel_draw_label_text(Panel * p, GtkWidget * label, char * text, gboolean bold, gboolean custom_color);
extern GtkWidget * create_generic_config_dlg(const char * title, GtkWidget * parent,
    GSourceFunc apply_func, Plugin * plugin, const char * name, ...);
extern gboolean plugin_button_press_event(GtkWidget * widget, GdkEventButton * event, Plugin * plugin);

int lxpamonConstructor(Plugin * plugin, char ** config)
{
    GtkWidget * label = gtk_label_new(NULL);
    plugin->pwid = gtk_event_box_new();
    gtk_container_add(GTK_CONTAINER(plugin->pwid), GTK_WIDGET(label));
    g_signal_connect(G_OBJECT(plugin->pwid), "button_press_event", G_CALLBACK(plugin_button_press_event), plugin);
    gtk_widget_show_all(plugin->pwid);
    PluginData * plug_data = g_new0(PluginData, 1);
    plug_data->label = label;
    lxpamonInitConfig(config, plug_data);
    plugin->priv = plug_data;
    PamonInitData pamon_init_data;
    memset(&pamon_init_data, 0, sizeof(PamonInitData));
    pamon_init_data.volume_callback = (PamonVolumeChangedCallback)pamonVolumeChanged;
    pamon_init_data.error_callback = (PamonErrorCallback)pamonError;
    pamon_init_data.userdata = plugin;
    pamon_init_data.sink_id = plug_data->sink;
    Pamon * pamon = pamonInit(&pamon_init_data);
    plug_data->pamon = pamon;
    return TRUE;
}

void lxpamonInitConfig(char ** src, PluginData * plug_data)
{
    line str;
    str.len = 256;
    while(lxpanel_get_line(src, &str))
    {
        if(strcmp(CONFIG_FORMAT, str.t[0]) == 0)
            plug_data->format = fixPrintfTemplatePlaceholderOccurences(g_strdup(str.t[1]),
                ALLOWED_FORMAT, INVALID_FORMAT_SYMBOL);
        else if(strcmp(CONFIG_SINK, str.t[0]) == 0)
            sscanf(str.t[1], "%i", &plug_data->sink);
        else if(strcmp(CONFIG_BOLD, str.t[0]) == 0)
            plug_data->bold_font = str2num(bool_pair, str.t[1], 0);
    }
    if(!plug_data->format)
        plug_data->format = g_strdup(DEFAULT_FORMAT);
}

void lxpamonDestructor(Plugin * plugin)
{
    PluginData * plug_data = (PluginData *)plugin->priv;
    pamonClose(plug_data->pamon);
    g_free(plug_data->format);
    g_free(plug_data);
}

void lxpamonConfigure(Plugin * plugin, GtkWindow * parent)
{
    PluginData * data = (PluginData *)plugin->priv;
    GtkWidget * dlg = create_generic_config_dlg(_(plugin->class->name), GTK_WIDGET(parent),
        (GSourceFunc)lxpamonApplyConfiguration, plugin,
        _("Pulseaudio sink"), &data->sink, CONF_TYPE_INT,
        _("Volume display format"), &data->format, CONF_TYPE_STR,
        _("Use %i to print current volume. Use %% to print the % mark."), NULL, CONF_TYPE_TRIM,
        _("Bold font"), &data->bold_font, CONF_TYPE_BOOL,
        NULL);
    gtk_window_present(GTK_WINDOW(dlg));
}

void lxpamonApplyConfiguration(Plugin * plugin)
{
    PluginData * plug_data = (PluginData *)plugin->priv;
    pamonSetSinkId(plug_data->pamon, plug_data->sink);
    fixPrintfTemplatePlaceholderOccurences(plug_data->format, ALLOWED_FORMAT, INVALID_FORMAT_SYMBOL);
    lxpamonDrawVolume(plugin);
}

static void lxpamonDrawVolume(Plugin * plugin)
{
    PluginData * plug_data = (PluginData *)plugin->priv;
    char * format = plug_data->format ? plug_data->format : "%%i";
    char * buf = (char *)malloc(strlen(format) + 4);
    if(INVALID_VOLUME == plug_data->current_volume)
        strcpy(buf, "ERROR");
    else
        sprintf(buf, plug_data->format, plug_data->current_volume);
    panel_draw_label_text(plugin->panel, plug_data->label, buf, plug_data->bold_font, TRUE);
    free(buf);
}

void lxpamonSaveConfig(Plugin * plugin, FILE * file)
{
    PluginData * plug_data = (PluginData *)plugin->priv;
    lxpanel_put_str(file, CONFIG_FORMAT, plug_data->format);
    lxpanel_put_int(file, CONFIG_SINK, plug_data->sink);
    lxpanel_put_bool(file, CONFIG_BOLD, plug_data->bold_font);
}

void lxpamonPanelConfigurationChanged(Plugin * plugin)
{
    lxpamonDrawVolume(plugin);
}

void pamonVolumeChanged(uint32_t current_volume, Plugin * plugin)
{
    PluginData * plug_data = (PluginData *)plugin->priv;
    plug_data->current_volume = current_volume;
    lxpamonDrawVolume(plugin);
}

void pamonError(PamonError error, Plugin * plugin)
{
    fprintf(stderr, "Pulseaudio monitor error: %s\n", pamonTranslateError(error));
    PluginData * plug_data = (PluginData *)plugin->priv;
    if(plug_data)
    {
        plug_data->current_volume = INVALID_VOLUME;
        lxpamonDrawVolume(plugin);
    }
}

PluginClass lxpamon_plugin_class = {
    PLUGINCLASS_VERSIONING,
    type: "lxpamon",
    name: N_("Pulseaudio volume monitor"),
    version: "1.0",
    description: N_("Pulseaudio volume monitor plugin for LXPanel"),
    one_per_system: FALSE,
    expand_available: FALSE,
    constructor: lxpamonConstructor,
    destructor: lxpamonDestructor,
    config: lxpamonConfigure,
    save: lxpamonSaveConfig,
    panel_configuration_changed: lxpamonPanelConfigurationChanged
};


